package ru.agiledev.aos.analyzer;

import ru.agiledev.aos.commons.dto.QType;
import ru.agiledev.aos.commons.dto.SemanticQuery;
import ru.agiledev.aos.commons.dto.LightWord;
import ru.agiledev.aos.core.util.QueryUtils;

import java.util.*;

/**
 * Objects of Ineterest finder class. Contains methods for parsing query depending on its type.
 * todo: one iteration parser - we really can do it
 *
 * Created by a.kirillov
 * Date: 11/6/11 Time: 10:34 PM
 */
public class QueryParser {

    /**
     * Main parsing method. Takes pre-formed semantic query with defined query type and stemmed query object. When parsing is complete
     * SemanticQuery object is filled with defined distinctive objects, objects of interests and additive objects depending on input query.
     * @param semanticQuery SemanticQuery object
     */
    public void parse(SemanticQuery semanticQuery){
        List<LightWord> result;
        QType type = semanticQuery.getQuestionType();
        List<LightWord> query = semanticQuery.getTransformedQuery();

        switch (type){
            case STRUCTURE_DESCRIPTION:{
                //Исключение: "Из чего состоит Х?"
                if(query.get(0).getStems().contains("из")&&query.get(1).getStems().contains("что")){
                    for(int i=2; i<query.size();i++){
                        if(query.get(i).getStems().contains("состоять")){
                            result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), Dictionaries.getInstance().getStructureDescriptionEmptyChainProducers());
                            semanticQuery.setDistinctiveObject(null);
                            semanticQuery.setFirstObject(result);
                            return;
                        }
                    }
                }
                //Исключение: "Из каких частей состоит Х?"
                if(query.get(0).getStems().contains("из")&&query.get(1).getStems().contains("какой")){
                    for(int i=2; i<query.size();i++){
                        if(query.get(i).getStems().contains("состоять")){
                            result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), Dictionaries.getInstance().getStructureDescriptionEmptyChainProducers());
                            semanticQuery.setDistinctiveObject(null);
                            semanticQuery.setFirstObject(result);
                            return;
                        }
                    }
                }

                //if extra cases are analyzed and result is null, the common structure is being analyzed
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getStructureDescriptionFlags(), Dictionaries.getInstance().getStructureDescriptionEmptyChainProducers());
                return;
            }
            case CHARACTERISTICS_DESCRIPTION: {
                //if extra cases are analyzed and result is null, the common structure is being analyzed
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getCharacteristicsDescriptionFlags(), Dictionaries.getInstance().getCharacteristicsDescriptionEmptyChainProducers());
                return;
            }
            case WORK_DESCRIPTION:{
                //if extra cases are analyzed and result is null, the common structure is being analyzed
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getWorkDescriptionFlags(), Dictionaries.getInstance().getWorkDescriptionEmptyChainProducers());
                return;
            }
            case FUNCTIONS_DESCRIPTION:{
                if(query.get(0).getStems().contains("за")&&query.get(1).getStems().contains("что")){
                    for(int i=2; i<query.size();i++){
                        if(query.get(i).getStems().contains("отвечать")){
                            result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), Dictionaries.getInstance().getFunctionsDescriptionEmptyChainProducers());
                            semanticQuery.setDistinctiveObject(null);
                            semanticQuery.setFirstObject(result);
                            return;
                        }
                    }
                }

                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getFunctionsDescriptionFlags(), Dictionaries.getInstance().getFunctionsDescriptionEmptyChainProducers());
                return;
            }
            case MISSION_DESCRIPTION:{
                if(query.get(0).getStems().contains("зачем")){
                    for(int i=1; i<query.size();i++){
                        if(query.get(i).getStems().contains("нужный")){
                            result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), Dictionaries.getInstance().getMissionDescriptionFlags());
                            semanticQuery.setDistinctiveObject(null);
                            semanticQuery.setFirstObject(result);
                            return;
                        }
                    }
                }
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getMissionDescriptionFlags(), Dictionaries.getInstance().getMissionDescriptionEmptyChainProducers());
                return;
            }
            case USAGE_DESCRIPTION:{
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getUsageDescriptionFlags(), Dictionaries.getInstance().getUsageDescriptionEmptyChainProducers());
                return;
            }
            case CORRESPONDS_TO_DESCRIPTION:{
                if((query.get(0).getStems().contains("к")&&query.get(1).getStems().contains("что"))||(query.get(0).getStems().contains("к")&&query.get(1).getStems().contains("кто"))){
                    for(int i=2; i<query.size();i++){
                        if(query.get(i).getStems().contains("относиться")){
                            result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), Dictionaries.getInstance().getCorrespondsToDescriptionFlags());
                            semanticQuery.setDistinctiveObject(null);
                            semanticQuery.setFirstObject(result);
                            return;
                        }
                    }
                }

                //all other cases for this query type are covered with this method
                correspondsToAnalysis(semanticQuery);
                return;
            }
            case DIFFERENCES_DESCRIPTION:{

                twoObjectsQueriesAnalysis(semanticQuery, Dictionaries.getInstance().getDifferencesDescriptionFlags(),
                        Dictionaries.getInstance().getDifferencesDescriptionEmptyChainProducers(),
                        Dictionaries.getInstance().getDifferencesDescriptionConjunctionPointers());

                return;
            }
            case COMMONS_DESCRIPTION:{
                twoObjectsQueriesAnalysis(semanticQuery, Dictionaries.getInstance().getCommonsDescriptionFlags(),
                        Dictionaries.getInstance().getCommonsDescriptionEmptyChainProducers(),
                        Dictionaries.getInstance().getCommonsDescriptionConjunctionPointers());

                return;
            }
            case FEATURES_DESCRIPTION:{
                featuresDescriptionAnalysis(semanticQuery);
                return;
            }
            case POSSIBILITIES_DESCRIPTION:{
                processStandardQuestionLayout(semanticQuery, Dictionaries.getInstance().getPossibilitiesDescriptionFlags(), Dictionaries.getInstance().getPossibilitiesDescriptionEmptyChainProducers());
                return;
            }
            case GOALS_DESCRIPTION: {
                processGoalsDescriptionQuestion(semanticQuery);
                return;
            }
            case SETS_CHANGES_DESCRIPTION:{
                processSetChangesQuery(semanticQuery);
                //todo: switch hierarchical projects

                return;
            }
        }
    }

    /**
     * Method return the tail of query containing objects of interest filtered from empty chain producers
     * @param subQuery subset of initial list of words
     * @param emptyChains empty chains dictionary for current subquery depending on query type
     * @return list of LightWords representing the object of interest situated at the end of the query
     */
    private List<LightWord> getRestAsObjectOfInterest(QType type, List<LightWord> subQuery, Set<String> emptyChains){
        List<LightWord> result = new ArrayList<LightWord>();

        boolean extraTrailing = true;
        for(int i=0; i< subQuery.size();i++){

            LightWord lightWord = subQuery.get(i);
            if(!QueryUtils.isWordStemsInDictionary(lightWord, emptyChains)){

                if(type.equals(QType.FUNCTIONS_DESCRIPTION)){
                    if(extraTrailing&&lightWord.getStems().contains("возлагать")){
                        if(subQuery.size()>(1+i)){
                            if(subQuery.get(i+1).getStems().contains("на")){
                                i = i+1;
                                result.removeAll(result);
                                extraTrailing = false;
                                continue;
                            }
                        }
                    }
                }

                result.add(lightWord);
            } else {
                //обработка ситуации вида "какими характеристиками главным образом обладает X?"
                result.removeAll(result);
            }
        }

        return result;
    }

    /**
     * Method return the tail of query containing objects of interest filtered from empty chain producers
     * differs from getRestAsObjectOfInterest in not clearing OI list, but just stepping over empty chain producer
     * @param subQuery subset of initial list of words
     * @param emptyChains empty chains dictionary for current subquery depending on query type
     * @return list of LightWords representing the object of interest situated at the end of the query
     */
    private List<LightWord> getRestAsObjectOfInterestSmooth(QType type, List<LightWord> subQuery, Set<String> emptyChains){
        List<LightWord> result = new ArrayList<LightWord>();

        boolean extraTrailing = true;
        for(int i=0; i< subQuery.size();i++){

            LightWord lightWord = subQuery.get(i);
            if(!QueryUtils.isWordStemsInDictionary(lightWord, emptyChains)){

                if(type.equals(QType.FUNCTIONS_DESCRIPTION)){
                    if(extraTrailing&&lightWord.getStems().contains("возлагать")){
                        if(subQuery.size()>(1+i)){
                            if(subQuery.get(i+1).getStems().contains("на")){
                                i = i+1;
                                result.removeAll(result);
                                extraTrailing = false;
                                continue;
                            }
                        }
                    }
                }

                result.add(lightWord);
            }
        }

        return result;
    }

    /**
     *  Method provides common functionality for defining objects of interest in queries which structure is common
     * @param semanticQuery input query as SemanticQuery
     * @param allowedDictionary allowed flags
     * @param emptyChainProducers empty chain producers
     */
    private void processStandardQuestionLayout(SemanticQuery semanticQuery, HashSet<String> allowedDictionary, HashSet<String> emptyChainProducers){
        List<LightWord> result;
        List<LightWord> query = semanticQuery.getTransformedQuery();

        for(int i=0; i<query.size();i++){
            if(QueryUtils.isWordStemsInDictionary(query.get(i), allowedDictionary)){

                if(semanticQuery.getQuestionType().equals(QType.MISSION_DESCRIPTION)){
                    result = getRestAsObjectOfInterestSmooth(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), emptyChainProducers);
                    semanticQuery.setDistinctiveObject(query.get(i));
                    semanticQuery.setFirstObject(result);
                    return;
                }

                result = getRestAsObjectOfInterest(semanticQuery.getQuestionType(), query.subList(i+1, query.size()), emptyChainProducers);
                semanticQuery.setDistinctiveObject(query.get(i));
                semanticQuery.setFirstObject(result);

                if(semanticQuery.getQuestionType().equals(QType.USAGE_DESCRIPTION)){
                    List<LightWord> additive = leftAdditionAnalysys(query.subList(0, i), Dictionaries.getInstance().getUsageDescriptionAdditiveEmptyChainProducers());
                    semanticQuery.setAdditionalObject(additive);
                }


            }
        }
    }

    /**
     * Extra-method for left-part analysis of queries that need some additional information like "В какой отрасли используется красный лазер?"
     * @param query left part of query
     * @param addicitveEmptyChainProducers addition empty chain producers
     * @return list of additions as LightWord objects
     */
    private List<LightWord> leftAdditionAnalysys(List<LightWord> query, HashSet<String> addicitveEmptyChainProducers){
        List<LightWord> result = new ArrayList<LightWord>();
        for(int i=0; i<query.size();i++){
            if(query.get(i).getStems().contains("в")){
                if((i+1)<query.size()){
                    if(QueryUtils.isWordStemsInDictionary(query.get(i+1), addicitveEmptyChainProducers)){
                        i++;
                        continue;
                    }
                }
            } else {
                if(!QueryUtils.isWordStemsInDictionary(query.get(i), addicitveEmptyChainProducers)){
                    result.add(query.get(i));
                }
            }
        }
        return result;

        /*
          как в металлургии в основном применяется Х
          как главным образом в европе используется газ

          каков главный принцип использования Х
        */
        /*
        В какой отрасли применяется Х?
        Как в отрасли применяется Х?
        Как в отрасли главным образом применяется х?

        в -> какой, основном, принципе,
        главным - образом

        */
    }

    /**
     * Method for corresponds to query analysis and additive object capturing
     * @param semanticQuery initial SemanticQuery object
     */
    private void correspondsToAnalysis(SemanticQuery semanticQuery){
        List<LightWord> query = semanticQuery.getTransformedQuery();

        List<LightWord> object = new ArrayList<LightWord>();
        List<LightWord> addition = new ArrayList<LightWord>();
        boolean objectFlag = false;

        for(int i=0; i<query.size();i++){
            if(QueryUtils.isWordStemsInDictionary(query.get(i), Dictionaries.getInstance().getCorrespondsToDescriptionFlags())){
                semanticQuery.setDistinctiveObject(query.get(i));

                for(int j=i+1; j<query.size();j++){

                    if(QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getCorrespondsToDescriptionEmptyChainPointers())){
                        objectFlag = true;
                        continue;
                    }

                    if(!objectFlag){
                        if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getCorrespondsToDescriptionEmptyChainProducers())){
                            addition.add(query.get(j));
                        }
                    } else {
                        if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getCorrespondsToDescriptionEmptyChainProducers())){
                            object.add(query.get(j));
                        }
                    }
                }
            }
        }
        semanticQuery.setAdditionalObject(addition);
        semanticQuery.setFirstObject(object);
    }

    /**
     * Method deals with queries that contain two different objects of interest and in further analysis their differences or commons must be defined
     * @param semanticQuery SemanticQuery object
     * @param allowedDictionary HashSet of flags for current query type
     * @param emptyChainProducers HashSet of empty chain producers for current query type
     * @param conjunctionPointers HashSet of conjunction pointers or delimiters between objects of interest for current query type
     */
    private void twoObjectsQueriesAnalysis(SemanticQuery semanticQuery, HashSet<String> allowedDictionary, HashSet<String> emptyChainProducers, HashSet<String> conjunctionPointers){
        List<LightWord> query = semanticQuery.getTransformedQuery();
        List<LightWord> firstObject = new ArrayList<LightWord>();
        List<LightWord> secondObject = new ArrayList<LightWord>();

        boolean isSecondObject = false;

        for(int i=0; i<query.size();i++){

            if(QueryUtils.isWordStemsInDictionary(query.get(i), allowedDictionary)){
                semanticQuery.setDistinctiveObject(query.get(i));

                for(int j=i+1; j<query.size();j++){
                    if(query.get(j-1).getStems().contains("общий")&&query.get(j).getStems().contains("черта")) continue;

                    if(QueryUtils.isWordStemsInDictionary(query.get(j), conjunctionPointers)){
                        isSecondObject = true;
                        continue;
                    }

                    if(!isSecondObject){
                        if(!QueryUtils.isWordStemsInDictionary(query.get(j), emptyChainProducers)){
                            firstObject.add(query.get(j));
                        } else {
                            firstObject.removeAll(firstObject);
                        }
                    } else {
                        if(!QueryUtils.isWordStemsInDictionary(query.get(j), emptyChainProducers)){
                            secondObject.add(query.get(j));
                        } else {
                            secondObject.removeAll(secondObject);
                        }
                    }
                }
            }
        }

        //we should perform search of first object on the left side of flag in case if it is not defined properly
        if(isSecondObject&&(firstObject.size()==0)){
            for(int i=0; i<query.size();i++){
                if(!QueryUtils.isWordStemsInDictionary(query.get(i), allowedDictionary)){
                    if(!QueryUtils.isWordStemsInDictionary(query.get(i), emptyChainProducers)){
                        firstObject.add(query.get(i));
                    }
                } else break;
            }
        } else if(!isSecondObject){          //we need this approach if there is no conjunction. Example: "Чем X несоответствует Y?"
            secondObject.addAll(firstObject);
            firstObject.removeAll(firstObject);

            for(int i=0; i<query.size();i++){
                if(!QueryUtils.isWordStemsInDictionary(query.get(i), allowedDictionary)){
                    if(!QueryUtils.isWordStemsInDictionary(query.get(i), emptyChainProducers)){
                        firstObject.add(query.get(i));
                    }
                } else break;
            }
        }


        semanticQuery.setFirstObject(firstObject);
        semanticQuery.setSecondObject(secondObject);
    }

    /**
     * Method provides features description queries analysis
     * @param semanticQuery SemanticQuery object
     */
    private void featuresDescriptionAnalysis(SemanticQuery semanticQuery) {
        List<LightWord> query = semanticQuery.getTransformedQuery();

        List<LightWord> firstObject = new ArrayList<LightWord>();
        List<LightWord> secondObject = new ArrayList<LightWord>();
        List<LightWord> addition = new ArrayList<LightWord>();

        boolean objectFlag = false;
        /*
        //Features descriptions questions section
    String[] features = {
            "Какие особенности есть у Х?",
            "Каковы основные отличительные черты Х?",

            "специфика Х",
            "Каковы главные отличительные черты Х?",
            "В чем уникальность Х?",
            "главные отличительные черты Х",

            "чем Х уникален?",
            "В чем Х особенный?",
            "В чем Х специфичный?",
            "Каковы особенности работы Х в ситуации У?",
            "отличительные черты функционирования Х при У?",
            "ключевые особенности действия Х в обстоятельствах У",
            "Как ведет себя Х в условиях У?",
            "Как функционирует Х в обстоятельствах У?",
            "Как действует Х в условиях У?"};

    String[] featuresExtended = {
            "Каковы особенности Х?",
            "Каковы отличительные черты Х?",

            "Какие особенности имеет Х?",
            "Какими особенностями обладает Х?",
            "В чем уникальность Х?",
            "отличительные черты Х?",
            "В чем особенности Х?",
            "В чем Х уникален?",
            "чем Х особенный?",
            "Каковы особенности работы Х в ситуации У?",
            "Каковы отличительные черты функционирования Х при У?",
            "Каковы особенности действия Х в обстоятельствах У?",
            "Как ведет себя Х в условиях У?",
            "Как работает Х в обстоятельствах У?",
            "Как действует Х в ситуации У?"};
        */
        for(int i=0; i<query.size();i++){
            //if firstObject found
            if(QueryUtils.isWordStemsInDictionary(query.get(i), Dictionaries.getInstance().getFeaturesDescriptionFlags())){

                semanticQuery.setDistinctiveObject(query.get(i));
                boolean flag = false;
                for(int j=i+1; j<query.size();j++){
                    if(query.get(j-1).getStems().contains("отличительный")&&query.get(j).getStems().contains("черта")) continue;
                    if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionEmptyChainProducers())){
                        if(QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionAdditiveEmptyChainProducers())){
                            addition.add(query.get(j));
                            continue;
                        }

                        if(QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionConjunctionPointers())){
                            flag = true;
                            continue;
                        }

                        if(flag){
                            secondObject.add(query.get(j));
                        } else {
                            firstObject.add(query.get(j));
                        }

                    }
                }

                /*
                "чем Х уникален?"
                "В чем Х особенный?"
                */
                if(firstObject.size()==0){
                    for(int j=0; j<query.size();j++){
                        if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionFlags())){
                            if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionEmptyChainProducers())
                                    &&!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionAdditiveEmptyChainProducers())){
                                firstObject.add(query.get(j));
                            }
                        } else break;
                    }
                }
                semanticQuery.setAdditionalObject(addition);
                semanticQuery.setFirstObject(firstObject);
                semanticQuery.setSecondObject(secondObject);
                return;

            } else if(QueryUtils.isWordStemsInDictionary(query.get(i), Dictionaries.getInstance().getFeaturesDescriptionAdditiveEmptyChainProducers())){ // and here if firstObject is not found
                /*Как работает Х в обстоятельствах У?*/
                boolean flag = false;
                addition.add(query.get(i));
                for(int j=i+1; j<query.size();j++){
                    if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionEmptyChainProducers())){

                        if(QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getFeaturesDescriptionConjunctionPointers())){
                            flag = true;
                            continue;
                        }

                        if(flag){
                            secondObject.add(query.get(j));
                        } else {
                            firstObject.add(query.get(j));
                        }
                    }
                }
                semanticQuery.setAdditionalObject(addition);
                semanticQuery.setFirstObject(firstObject);
                semanticQuery.setSecondObject(secondObject);
                return;
            }

        }
    }

    /**
     * Method parses goals queries and defines date addition for SemanticQuery object
     * @param semanticQuery SemanticQuery object
     */
    private void processGoalsDescriptionQuestion(SemanticQuery semanticQuery){
        List<LightWord> query = semanticQuery.getTransformedQuery();
        List<LightWord> firstObject = new ArrayList<LightWord>();

        /*
         "Какие успехи были у компании Х в прошлом году?",
            "Достижения X позапрошлый год",
            "каковы основные неудачи Х в прошедшем году?",
            "Каких успехов добилось X за текущий год?",


            "Какие неудачи были у компании Х в 2010?",
            "Достижения X 11 год",
            "главные неудачи Х в 2009 году?",
            "Каких успехов добилось X к 2008?",

            "Какие неудачи имела компания Х год назад?",
            "успехи X 11 лет назад",
            "главные успехи Х пять лет назад",

            "Чего добилась компания Х в прошлом году?",
            "Чего достиг холдинг X позапрошлый год",

            "Чего достигло Х в 2009 году?",
            "Чего добились X к 2008?",

            "Чего добилась компания Х год назад?",
            "Чего достиг X 11 лет назад"
        */

        for(int i=0; i<query.size();i++){
            if(QueryUtils.isWordStemsInDictionary(query.get(i), Dictionaries.getInstance().getGoalsDescriptionFlags())){
                semanticQuery.setDistinctiveObject(query.get(i));

                for(int j=i+1; j<query.size();j++){
                    if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getGoalsDescriptionEmptyChainProducers())
                            &&!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getGoalsDescriptionFlags())){//for case when we have "Каких успехов добился.."

                        if(restIsDate(semanticQuery, j)) return;

                        firstObject.add(query.get(j));
                        semanticQuery.setFirstObject(firstObject);
                    }

                }
            }
        }


    }

    /**
     * Method defines whether the rest of query contains date definition
     * @param semanticQuery SemanticQuery object
     * @param index where to start
     * @return true if date found + addition object is set, false in other case
     */
    private boolean restIsDate(SemanticQuery semanticQuery, int index){
        List<LightWord> query = semanticQuery.getTransformedQuery();

        HashSet<String> current = null;
        switch (semanticQuery.getQuestionType()){
            case GOALS_DESCRIPTION: current = Dictionaries.getInstance().getGoalsDescriptionAdditiveEmptyChainProducers(); break;
            case SETS_CHANGES_DESCRIPTION: current = Dictionaries.getInstance().getSetChangesDescriptionAdditiveEmptyChainProducers(); break;
        }

        List<LightWord> dateObject = new ArrayList<LightWord>();

        //if {"прошедший", "прошлый", "позапрошлый", "текущий"} presented
        if(QueryUtils.isWordStemsInDictionary(query.get(index), current)){
            int delta = 0;
            if(query.get(index).getStems().contains("прошедший")||query.get(index).getStems().contains("прошлый")) delta = -1;
            else if(query.get(index).getStems().contains("позапрошлый")) delta = -2;

            if((index+1)<query.size()){
                if(query.get(index+1).getStems().contains("год")){
                    query.get(index + 1).setValue("год");
                    dateObject.add(new LightWord("" + (getCurrentYear() + delta), new HashSet<String>()));

                    dateObject.add(query.get(index + 1));
                    semanticQuery.setDateObject(dateObject);

                    if(query.size() == (index+1)+1){
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        }

        //if number is presented
        if(isNumber(query.get(index).getValue())){
            if((index+2)<query.size()){
                if(query.get(index+1).getStems().contains("год")&&query.get(index+2).getStems().contains("назад")){
                    query.get(index + 1).setValue("год");
                    dateObject.add(new LightWord("" + (getCurrentYear() - Integer.parseInt(query.get(index).getValue())), new HashSet<String>()));
                    dateObject.add(query.get(index + 1));
                    semanticQuery.setDateObject(dateObject);

                    if(query.size() == (index+2)+1){
                        return true;
                    } else {
                        return false;
                    }
                }
            } else if((index+1)<query.size()){
                if(query.get(index+1).getStems().contains("год")){
                    query.get(index + 1).setValue("год");
                    dateObject.add(query.get(index));
                    dateObject.add(query.get(index + 1));
                    semanticQuery.setDateObject(dateObject);

                    if(query.size() == (index+1)+1){
                        return true;
                    } else {
                        return false;
                    }
                }
            } else {//if no additional info presented
                dateObject.add(query.get(index));
                semanticQuery.setDateObject(dateObject);

                if(query.size() == (index)+1){
                    return true;
                } else {
                    return false;
                }
            }

        }

        //if no number is presented but we have "год назад"
        if(query.get(index).getStems().contains("год")){
            query.get(index).setValue("год");
            if(((index+1)<query.size())&&(query.get(index+1).getStems().contains("назад"))){
                dateObject.add(new LightWord("" + (getCurrentYear() - 1), new HashSet<String>()));
                dateObject.add(query.get(index));
                semanticQuery.setDateObject(dateObject);

                if(query.size() == (index+1)+1){
                    return true;
                } else {
                    return false;
                }
            }
        }

        if(wordAsNumber(query.get(index).getValue())>0){
            if((index+2)<query.size()){
                if(query.get(index+1).getStems().contains("год")&&query.get(index+2).getStems().contains("назад")){
                    query.get(index + 1).setValue("год");
                    dateObject.add(new LightWord("" + (getCurrentYear() - wordAsNumber(query.get(index).getValue())), new HashSet<String>()));
                    dateObject.add(query.get(index + 1));
                    semanticQuery.setDateObject(dateObject);

                    if(query.size() == (index+2)+1){
                        return true;
                    } else {
                        return false;
                    }
                }
            } else if((index+1)<query.size()){
                if(query.get(index+1).getStems().contains("год")){
                    query.get(index + 1).setValue("год");
                    dateObject.add(new LightWord("" + (getCurrentYear() - wordAsNumber(query.get(index).getValue()))));
                    dateObject.add(query.get(index + 1));
                    semanticQuery.setDateObject(dateObject);

                    if(query.size() == (index+1)+1){
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        }
        return false;
    }


    /**
     * Method for set changes queries analysis
     * @param semanticQuery SemanticQuery object
     */
    private void processSetChangesQuery(SemanticQuery semanticQuery){
        List<LightWord> query = semanticQuery.getTransformedQuery();

        List<LightWord> firstObject = new ArrayList<LightWord>(); // составляющая часть (департамент, руководство)
        List<LightWord> secondObject = new ArrayList<LightWord>();// общая часть (компания)

        boolean firstObjectFound = false;
        boolean secondObjectFound = false;
        /*
        Какие изменения были в структуре компании Х в департаменте У?
        Изменения структуры компании Х
        Какие изменения были в структуре фирмы Х?
        Каковы изменения структуры предприятия Х в департаменте У?


        Какие структурные изменения коснулись департамента У компании Х?
        Какие изменения произошли в составе компании Х?
        Какие изменения затронули состав руководства компании Х?
        Каковы структурные изменения руководства компании Х?


        Какие изменения в составе руководства были у компании Х?
        Изменения структуры департамента У компании Х
        Каковы изменения состава руководства предприятия Х?


        Какие изменения у компании Х в составе департамента У?
        Изменения компании Х в структуре руководства
        Каковы изменения компании Х в составе департамента У?


        Что изменилось в составе компании Х в департаменте У?
        Что изменилось в структуре компании Х?
        Как изменилась структура компании Х департамента У?
        Как изменился состав компании Х в руководстве?

        Что изменилось в составе руководства предприятия Х?
        Как изменилась структура руководства фирмы Х?
        Что изменилось в составе департамента У компании Х?
        Как изменился состав департамента У компании Х?

        Что изменилось в компании Х в составе руководства?
        Что изменилось в фирме Х в структуре департамента У?
        */


        for(int i=0; i<query.size();i++){
            if(QueryUtils.isWordStemsInDictionary(query.get(i), Dictionaries.getInstance().getSetChangesDescriptionFlags())){
                semanticQuery.setDistinctiveObject(query.get(i));
                for(int j=i+1; j<query.size(); j++){
                    if(!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getSetChangesEmptyChainProducers())
                            &&!QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getSetChangesDescriptionSecondaryFlags())){


                        if(firstObjectFound &&QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getSetChangesDomainWords())){
                            query.get(j).setValue(query.get(j).getStems().iterator().next());//use first stem ("компания", "департамент")
                            secondObjectFound = true;
                        }

                        if(QueryUtils.isWordStemsInDictionary(query.get(j), Dictionaries.getInstance().getSetChangesDomainWords())){
                            query.get(j).setValue(query.get(j).getStems().iterator().next());//use first stem ("компания", "департамент")
                            firstObjectFound = true;
                        }


                        if(restIsDate(semanticQuery, j)) return;

                        //we should check time period features for word if at least one domain word found
                        if(firstObjectFound||secondObjectFound){
                            semanticQuery.setFirstObject(firstObject);
                            semanticQuery.setSecondObject(secondObject);
                        }


                        //first occurrence of domain word
                        if(firstObjectFound&&!secondObjectFound){
                            firstObject.add(query.get(j));
                        } else if(firstObjectFound&&secondObjectFound){
                            secondObject.add(query.get(j));
                        }

                    }
                }
            }

        }
    }

    private int getCurrentYear(){
        Calendar c = new GregorianCalendar();
        return c.get(Calendar.YEAR);
    }

    private boolean isNumber(String num){
        try{
            Integer.parseInt(num);
        } catch(NumberFormatException nfe) {
            return false;
        }
        return true;
    }

    private int wordAsNumber(String word){
        if("один".equalsIgnoreCase(word)) return 1;
        else   if("два".equalsIgnoreCase(word)) return 2;
        else   if("пару".equalsIgnoreCase(word)) return 2;
        else   if("три".equalsIgnoreCase(word)) return 3;
        else   if("четыре".equalsIgnoreCase(word)) return 4;
        else   if("пять".equalsIgnoreCase(word)) return 5;
        else   if("шесть".equalsIgnoreCase(word)) return 6;
        else   if("семь".equalsIgnoreCase(word)) return 7;
        else   if("восемь".equalsIgnoreCase(word)) return 8;
        else   if("девять".equalsIgnoreCase(word)) return 9;
        else   if("десять".equalsIgnoreCase(word)) return 10;

        return -1;
    }
}
